/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 * Date:             2011.08.12                                          *
 *                                                                       *
 *************************************************************************/

//declaration header
#include "COMMON/info/AttributeInfo.h"

//COMMON headers
#include "COMMON/attr/Attribute.h"
#include "COMMON/base/DefaultParameters.h"
#include "COMMON/tbox/Utilities.h"
#include "COMMON/tbox/InputDatabase.h"
#include "COMMON/tbox/LogMessage.h"

#include <fstream>


namespace FreeMAPs
{

AttributeInfo::AttributeInfo (
    const std::string& object_name) :
    Parent ("base_information", object_name),
    d_default_attr (new Attribute(this->get_full_name(), "Al.mat") )
{}



AttributeInfo::~AttributeInfo()
{
    this->clear();
}



void
AttributeInfo::clear()
{
    Utilities::clear_pointer_object (d_attrs);
    Utilities::clear_pointer_object (d_default_attr);
}



void
AttributeInfo::add_attribute(
        const std::string attribute_name,
        const std::string attr_db_file_name)
{
    Attribute* attrib = new Attribute (this->get_full_name(), attribute_name);
    attrib->set_attr_db_file_name(attr_db_file_name);

    d_attrs.insert(std::make_pair(attribute_name, attrib));
}



bool
AttributeInfo::check_all_info_db (
        const InputDatabase* db)
{
    //attribute_names
    if( !db->key_exists("attribute_names") )
    {
        FREEMAPS_ERROR("in \"attribute_info\", can not find  \"attribute_names\" \n");
        return false;
    }
    if( !db->is_string("attribute_names") )
    {
        FREEMAPS_ERROR("in \"attribute_info\", \"attribute_names\" should be string \n");
        return false;
    }

    const std::vector<std::string>& attr_names = db->get_string_vector ("attribute_names");
    for (std::size_t i = 0; i < attr_names.size(); i++)
    {
        const std::string& attr_name = attr_names[i];

        if( db->key_exists(attr_name))
        {
            if( !db->is_database(attr_name) )
            {
                FREEMAPS_ERROR("in \"attribute_info\",  \"" + attr_name + "\", should be database, like this--> A \n{\n ......\n} \n");
                return false;
            }

            const InputDatabase* db_attr = db->get_database(attr_name);
            if( !db_attr->key_exists("attr_db_file_name") )
            {
                FREEMAPS_ERROR("in \"attribute_info\", in \"" + attr_name + "\", can not find  \"attr_db_file_name\" \n");
                return false;
            }
            if( !db_attr->is_string("attr_db_file_name") )
            {
                FREEMAPS_ERROR("in \"attribute_info\",  in \"" + attr_name + "\", \"attr_db_file_name\" should be string \n");
                return false;
            }
            //material file exist or not
            const std::string& file_name = db_attr->get_string("attr_db_file_name");
            std::ifstream fin(file_name);
            if( !fin )
            {
                FREEMAPS_ERROR("in \"attribute_info\", in \"" + attr_name + "\",  can not find the material file! \n");
                fin.close();
                return false;
            }
            fin.close();
        }
        else
        {
            FREEMAPS_ERROR("in \"attribute_info\", can not find database \"" + attr_name + "\" , but in \"attribute_names\" exist\n");
            return false;
        }
    }

    return true;
}



void
AttributeInfo::get_from_input (
        const InputDatabase* db)
{
    this->prepare_for_use (db);

    //check parameter
    db->insert_allowable_key ("default_attribute");
    db->insert_allowable_key_with_items ("attribute_names");
    db->check_allowable_keys();

    /*
     * build attribute_types
     */
    {
        if (db->key_exists ("attribute_names") && db->is_string("attribute_names"))
        {
            db->check_optional_key ("attribute_names", DataType::STRING, false, true);
            db->check_duplicated_string_value ("attribute_names");

            const std::vector<std::string>& attr_names = db->get_string_vector ("attribute_names");
            for (std::size_t i = 0; i < attr_names.size(); ++i)
            {
                const std::string& attr_name = attr_names[i];

                //exist && is database
                if(db->key_exists(attr_name) && db->is_database(attr_name))
                {
                    db->check_requisite_key (attr_name, DataType::DATABASE, false, false);

                    Attribute* attrib = new Attribute (this->get_full_name(), attr_name);
                    attrib->get_from_input (db->get_database (attr_name));

                    d_attrs.insert (std::make_pair (attr_name, attrib));
                }
            }
        }
    }

}



std::ostream&
operator << (
    std::ostream& os,
    /*const*/ AttributeInfo& rhs)
{
    os << "attribute_info" << RTN_FLAG << "{" << RTN_FLAG;

    /*
     * output attr_names
     */
    if (rhs.d_attrs.empty())
    {
        rhs.add_attribute("attr_Al", "Al.mat");//give a default
        os << LogMessage::get_log_info_from_map ("attribute_names", rhs.d_attrs, ONE_TAB) << RTN_FLAG;
    }
    else
    {
        os << LogMessage::get_log_info_from_map ("attribute_names", rhs.d_attrs, ONE_TAB) << RTN_FLAG;
    }

    os << "}";

    return os;
}

} //namespace FreeMAPs
